package indi.dbfmp.oio.gateway.filter;

import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSONObject;
import indi.dbfmp.web.common.dto.CommonResult;
import inid.dbfmp.oauth.api.context.UserInfoContext;
import inid.dbfmp.oauth.api.dto.VerifyTokenDto;
import inid.dbfmp.oauth.api.exception.CommonException;
import inid.dbfmp.oauth.api.service.JwtTokenService;
import io.micrometer.core.annotation.Counted;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;


/**
 * <p>
 *  全局权限过滤器
 * </p>
 *
 * @author dbfmp
 * @name: AuthGlobalFilter
 * @since 2020/10/11 2:49 下午
 */
@Slf4j
//过滤器优先级
@Order(0)
@Component
public class TokenGlobalFilter implements GlobalFilter {

    @Reference(check = false,group = "${spring.profiles.active}")
    private JwtTokenService jwtTokenService;
    @Autowired
    private MeterRegistry registry;
    private final String METRIC_NAME = "filer.token.global";

    @Counted(value = "filer.token.global",extraTags = {"URL","Token校验计数"},description = "Token校验计数")
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        log.info("TokenGlobalFilter开始");
        Timer.Sample sample = Timer.start(registry);
        String token = exchange.getRequest().getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        if (StrUtil.isBlank(token)) {
            return chain.filter(exchange);
        }
        //调用服务校验token
        try {
            VerifyTokenDto verifyTokenDto = jwtTokenService.verifyToken(token);
            MDC.put("userId",verifyTokenDto.getPayloadDto().getUserId());
            UserInfoContext.setUserInfoContext(verifyTokenDto.getPayloadDto());
            ServerHttpRequest request = exchange.getRequest().mutate().header("user", JSONObject.toJSONString(verifyTokenDto.getPayloadDto())).build();
            exchange = exchange.mutate().request(request).build();
        } catch (CommonException e) {
            log.error("token校验失败！",e);
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.OK);
            response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
            String body= JSONUtil.toJsonStr(CommonResult.failed(e.getResultCode(),e.getMessage()));
            DataBuffer buffer =  response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
            sample.stop(Timer.builder(METRIC_NAME)
                    .description("Token校验")
                    .tags("URL","Token校验")
                    .publishPercentileHistogram(true)
                    .register(registry));
            return response.writeWith(Mono.just(buffer));
        }catch (Exception e) {
            log.error("token校验异常！",e);
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.OK);
            response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
            String body= JSONUtil.toJsonStr(CommonResult.failed("token校验失败！"));
            DataBuffer buffer =  response.bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8));
            sample.stop(Timer.builder(METRIC_NAME)
                    .description("Token校验")
                    .tags("URL","Token校验")
                    .publishPercentileHistogram(true)
                    .register(registry));
            return response.writeWith(Mono.just(buffer));
        }finally {
            //MDC.remove("userId");
            UserInfoContext.removeUserInfo();
        }
        sample.stop(Timer.builder(METRIC_NAME)
                .description("Token校验")
                .tags("URL","Token校验")
                .publishPercentileHistogram(true)
                .register(registry));
        log.info("TokenGlobalFilter结束");
        return chain.filter(exchange);
    }
}
